package com.w3c.pragmatic.utils;

import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Objects;

/**
 * 数据运算
 *
 * @author wangdong
 * @since 2025/3/4 16:50
 */
public class BigDecimalUtil {

  public static final BigDecimal per = new BigDecimal("100");
  public static final BigDecimal thousand = new BigDecimal("1000");

  /**
   * 【加法】多个BigDecimal数据相加
   *
   * @param from 第1个加数
   * @param to 第2~n个加数
   * @return 计算结果
   */
  public static BigDecimal add(BigDecimal from, BigDecimal... to) {
    BigDecimal result = safe(from);
    if (to != null) {
      for (BigDecimal t : to) result = result.add(safe(t));
    }
    return result;
  }

  /**
   * 【加法】多个String相加
   *
   * @param from 第1个加数
   * @param to 第2~n个加数
   * @return 计算结果
   */
  public static String add(String from, String... to) {
    BigDecimal result = strToDecimalDefaultZero(from);
    if (to != null) {
      for (String t : to) result = add(result, t);
    }
    return toString(result);
  }

  /**
   * 【加法】第1个为BigDecimal第2个为String
   *
   * @param from 第1个加数
   * @param to 第2个加数
   * @return 计算结果
   */
  public static BigDecimal add(BigDecimal from, String to) {
    BigDecimal result = from;
    if (to != null && !to.isEmpty()) {
      result = result.add(strToDecimalDefaultZero(to));
    }
    return result;
  }

  /**
   * 【减法】多个BigDecimal数据相减
   *
   * @param from 被减数
   * @param to 减数
   * @return 计算结果
   */
  public static BigDecimal subtract(BigDecimal from, BigDecimal... to) {
    BigDecimal result = safe(from);
    if (to != null) {
      for (BigDecimal t : to) result = result.subtract(safe(t));
    }
    return result;
  }

  /**
   * 【减法】多个String数据相减
   *
   * @param from 被减数
   * @param to 减数
   * @return 计算结果
   */
  public static BigDecimal subtract(String from, String... to) {
    BigDecimal result = strToDecimalDefaultZero(from);
    if (to != null) {
      for (String t : to) result = result.subtract(strToDecimalDefaultZero(t));
    }
    return result;
  }

  /**
   * 【乘法】多个BigDecimal数据相乘
   *
   * @param from 第1个被乘数
   * @param to 第2~n个乘数
   * @return 计算结果
   */
  public static BigDecimal multiply(BigDecimal from, BigDecimal... to) {
    BigDecimal result = safe(from);
    if (to != null) {
      for (BigDecimal t : to) result = result.multiply(safe(t));
    }
    return result;
  }

  /**
   * 【乘法】多个String数据相乘
   *
   * @param from 第1个被乘数
   * @param to 第2~n个乘数
   * @return 计算结果
   */
  public static BigDecimal multiply(String from, String... to) {
    BigDecimal result = strToDecimalDefaultZero(from);
    if (to != null) {
      for (String t : to) result = result.multiply(safe(strToDecimalDefaultZero(t)));
    }
    return result;
  }

  /**
   * 【除法】两个BigDecimal数据相除(除数为0则返回0；除数为null则返回被除数)
   *
   * @param from 被除数
   * @param to 除数
   * @param scale 保留小数
   * @return 计算结果
   */
  public static BigDecimal divide(BigDecimal from, BigDecimal to, int scale) {
    BigDecimal result = safe(from);
    if (to == null) {
      return result;
    } else if (to.compareTo(BigDecimal.ZERO) == 0) {
      return BigDecimal.ZERO;
    } else {
      return result.divide(to, scale, RoundingMode.HALF_UP);
    }
  }

  /**
   * 【除法】两个BigDecimal数据相除(除数为0则返回0；除数为null则返回被除数)
   *
   * @param from 被除数
   * @param to 除数
   * @return 计算结果
   */
  public static BigDecimal divide(BigDecimal from, BigDecimal to) {
    return divide(from, to, 2);
  }

  /**
   * 【除法】两个String数据相除(除数为0则返回0；除数为null则返回被除数)
   *
   * @param from 被除数
   * @param to 除数
   * @param scale 保留小数
   * @return 计算结果
   */
  public static BigDecimal divideStr(String from, String to, int scale) {
    BigDecimal decimalFrom = strToDecimalDefaultNull(from);
    BigDecimal decimalTo = strToDecimalDefaultNull(to);
    return divide(decimalFrom, decimalTo, scale);
  }

  /**
   * 【百分比】计算百分比 66.6667
   *
   * @param from 被除数
   * @param to 除数
   * @return 结果
   */
  public static BigDecimal calcPer(BigDecimal from, BigDecimal to) {
    if (from == null || to == null) {
      return null;
    } else {
      from = multiply(from, per);
      return divide(from, to, 4);
    }
  }

  /**
   * 【百分级】百分级转成小数 121 -> 1.2100
   *
   * @param baseVal 千分级
   * @return 结果
   */
  public static BigDecimal divideHundred(BigDecimal baseVal) {
    BigDecimal safe = safe(baseVal);
    return divide(safe, per, 4);
  }

  /**
   * 【百分级】小数转百分级 1.21 -> 121.00
   *
   * @param baseVal 小数
   * @return 结果
   */
  public static BigDecimal multiplyHundred(BigDecimal baseVal) {
    BigDecimal safe = safe(baseVal);
    return multiply(safe, per);
  }

  /**
   * 【千分级】千分级转成小数 1210 -> 1.2100
   *
   * @param baseVal 千分级
   * @return 结果
   */
  public static BigDecimal divideThousand(BigDecimal baseVal) {
    BigDecimal safe = safe(baseVal);
    return divide(safe, thousand, 4);
  }

  /**
   * 【千分级】小数转千分级 1.21 -> 1210.00
   *
   * @param baseVal 小数
   * @return 结果
   */
  public static BigDecimal multiplyThousand(BigDecimal baseVal) {
    BigDecimal safe = safe(baseVal);
    return multiply(safe, thousand);
  }

  /**
   * 【比较大小】比较两个BigDecimal数据大小 返回int
   *
   * @param from 被比较数
   * @param to 比较数
   * @return 结果：大于0-from大；小于0-to大； 等于0-一样大
   */
  public static int compareTo(BigDecimal from, BigDecimal to) {
    return safe(from).compareTo(safe(to));
  }

  /**
   * 【比较大小】比较两个String数据大小 返回int
   *
   * @param from 被比较数
   * @param to 比较数
   * @return 结果：大于0-from大；小于0-to大； 等于0-一样大
   */
  public static int compareTo(String from, String to) {
    BigDecimal decimalFrom = strToDecimalDefaultZero(from);
    BigDecimal decimalTo = strToDecimalDefaultZero(to);
    return safe(decimalFrom).compareTo(safe(decimalTo));
  }

  /**
   * 【设置scale】 设置小数位数,四舍五入
   *
   * @param bigDecimal 被设置数
   * @param scale 位数
   * @return 结果
   */
  public static BigDecimal setScale(BigDecimal bigDecimal, int scale) {
    if (bigDecimal == null) {
      return null;
    }
    return bigDecimal.divide(new BigDecimal(1), scale, RoundingMode.HALF_UP);
  }

  /**
   * 【设置scale】 double-BigDecimal scale位小数
   *
   * @param value 被设置数
   * @param scale 位数
   * @return 结果
   */
  public static BigDecimal doubleValueSetScale(double value, int scale) {
    return setScale(new BigDecimal(value), scale);
  }

  // =============================================内部使用===============================================

  // 数据为空则返回Zero
  private static BigDecimal safe(BigDecimal target) {
    if (Objects.isNull(target)) {
      return BigDecimal.ZERO;
    } else {
      return target;
    }
  }

  // 字符串转BigDecimal 为空则返回Zero
  private static BigDecimal strToDecimalDefaultZero(String s) {
    return strToDecimal(s, BigDecimal.ZERO);
  }

  // 字符串转BigDecimal 为空则返回空
  private static BigDecimal strToDecimalDefaultNull(String s) {
    return strToDecimal(s, null);
  }

  // 字符串转BigDecimal 为空默认值defaultV
  private static BigDecimal strToDecimal(String s, BigDecimal defaultV) {
    if (ObjectUtils.isEmpty(s)) {
      return defaultV;
    }
    try {
      return new BigDecimal(s).setScale(4, RoundingMode.HALF_UP);
    } catch (Exception e) {
      return defaultV;
    }
  }

  // BigDecimal值如果为空转null
  private static BigDecimal decimalDefaultNull(BigDecimal val) {
    if (ObjectUtils.isEmpty(val)) {
      return null;
    }
    try {
      return val.setScale(4, RoundingMode.HALF_UP);
    } catch (Exception e) {
      return null;
    }
  }

  // BigDecimal值如果为空转BigDecimal-ZERO
  private static BigDecimal decimalDefaultZero(BigDecimal val) {
    return ObjectUtils.isEmpty(val) ? BigDecimal.ZERO : val;
  }

  // 转换为字符串 6位小数
  private static String toString(BigDecimal decimal) {
    DecimalFormat decimalFormat = new DecimalFormat("#.######");
    decimalFormat.setGroupingUsed(false);
    return decimal == null ? null : decimalFormat.format(decimal);
  }

  // 根据pattern格式化decimal数据
  private static String toString(BigDecimal decimal, String pattern) {
    DecimalFormat decimalFormat = new DecimalFormat(pattern);
    decimalFormat.setGroupingUsed(false);
    return decimal == null ? null : decimalFormat.format(decimal);
  }

  /** 字符串数value 据转成BigDecimal 默认值defaultV */
  private static BigDecimal strToDecimalToDefaultV(String value, BigDecimal defaultV, int scale) {
    if (ObjectUtils.isEmpty(value)) {
      return defaultV;
    }
    try {
      return new BigDecimal(value).setScale(scale, RoundingMode.HALF_UP);
    } catch (Exception e) {
      return defaultV;
    }
  }

  // 设置对象里面的所有的BigDecimal,保留小数位数scale位
  private static void handleBigDecimalScale(Object o, int scale) {
    Field[] fields = o.getClass().getDeclaredFields();
    for (Field field : fields) {
      try {
        field.setAccessible(true);
        if (field.getType() == BigDecimal.class) {
          Object v = field.get(o);
          if (v instanceof BigDecimal) {
            BigDecimal b = (BigDecimal) v;
            b = setScale(b, scale);
            field.set(o, b);
          }
        }
      } catch (Exception ignored) {

      }
    }
  }

}
